#pragma once

#include "Clause.h"

#include "ExecutableNode.h"
#include "OutputPin.h"

namespace uml {

Clause::Clause(const QString& umlType)
    : Element(umlType) {}

void Clause::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    Element::fromJson(json, errorList);
    JsonSerializable::fromJsonArray(bodys_, "bodys", json, errorList);
    JsonSerializable::fromJsonArray(bodyOutputs_, "bodyOutputs", json, errorList);
    decider_ = JsonSerializable::create<OutputPin>(json.value("decider"), errorList);

    JsonSerializable::fromJsonArray(predecessorClauses_, "predecessorClauses", json, errorList);
    JsonSerializable::fromJsonArray(successorClauses_, "successorClauses", json, errorList);
    JsonSerializable::fromJsonArray(tests_, "tests", json, errorList);
}

void Clause::toJson(QJsonObject& json) {
    Element::toJson(json);
    JsonSerializable::toJsonArray(bodys_, "bodys", json);
    JsonSerializable::toJsonArray(bodyOutputs_, "bodyOutputs", json);
    if (decider_) {
        QJsonObject decider_json;
        decider_->toJson(decider_json);
        json.insert("decider", decider_json);
    }
    JsonSerializable::toJsonArray(predecessorClauses_, "predecessorClauses", json);
    JsonSerializable::toJsonArray(successorClauses_, "successorClauses", json);
    JsonSerializable::toJsonArray(tests_, "tests", json);
}

/// <summary>
/// bodys getter
/// The set of ExecutableNodes that are executed if the test evaluates to true and
/// the Clause is chosen over other Clauses within the ConditionalNode that also
/// have tests that evaluate to true.
/// </summary>
vector<shared_ptr<ExecutableNode>>& Clause::bodys() {
    return bodys_;
}

/// <summary>
/// bodyOutputs getter
/// The OutputPins on Actions within the body section whose values are moved to the
/// result OutputPins of the containing ConditionalNode after execution of the body.
/// </summary>
vector<shared_ptr<OutputPin>>& Clause::bodyOutputs() {
    return bodyOutputs_;
}

/// <summary>
/// decider getter
/// An OutputPin on an Action in the test section whose Boolean value determines the
/// result of the test.
/// </summary>
shared_ptr<OutputPin> Clause::decider() const {
    return decider_;
}

/// <summary>
/// decider setter
/// An OutputPin on an Action in the test section whose Boolean value determines the
/// result of the test.
/// </summary>
void Clause::setDecider(shared_ptr<OutputPin> value) {
    decider_ = value;
}

/// <summary>
/// predecessorClauses getter
/// A set of Clauses whose tests must all evaluate to false before this Clause can
/// evaluate its test.
/// </summary>
vector<shared_ptr<Clause>>& Clause::predecessorClauses() {
    return predecessorClauses_;
}

/// <summary>
/// successorClauses getter
/// A set of Clauses that may not evaluate their tests unless the test for this
/// Clause evaluates to false.
/// </summary>
vector<shared_ptr<Clause>>& Clause::successorClauses() {
    return successorClauses_;
}

/// <summary>
/// tests getter
/// The set of ExecutableNodes that are executed in order to provide a test result
/// for the Clause.
/// </summary>
vector<shared_ptr<ExecutableNode>>& Clause::tests() {
    return tests_;
}

} // namespace uml
